﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using SharedLib.WinFormMVCFramework;
using TracyGUI.View;
using Tracy.DataModel;
using SharedLib;
using TracyGUI.Controller.EntryTabs;
using TracyGUI.View.UIComponent;
using TracyGUI.Model;
using SharedLib.Helpers;
using Tracy.Messages;
using Tracy.Handlers;
using SharedLib.MessageFramework.Messages;
using System.Windows.Forms;

namespace TracyGUI.Controller
{
    class EntryListViewController : ControllerBase<IEntryListView>, IController<IEntryListView>, IHasViewState
    {
        Entry _selectedEntry = null; 
        protected override IEntryListView ResolveView()
        {
            return Tracy.TracyFacade.Instance.DIContainer.Resolve<IEntryListView>();
        }
        EntryTabsViewController _entryTabsViewController = new EntryTabsViewController();
        UltraExplorerViewController _ueViewController = new UltraExplorerViewController();

        public EntryListViewController()
        {
            //Monitor View Events
            View.EntrySelected += new EventHandler<GenericEventArgs<Entry>>(View_EntrySelected);
            View.OpenEntryInNewTab += new EventHandler<GenericEventArgs<Entry>>(View_OpenEntryInNewTab);
            View.AllEntriesClicked += new EventHandler(View_AllEntriesClicked);
            View.CreateEntryClicked += new EventHandler(View_CreateEntryClicked);
            View.EditEntryClicked += new EventHandler<GenericEventArgs<Entry>>(View_EditEntryClicked);
            View.RemoveEntryClicked += new EventHandler<GenericEventArgs<Entry>>(View_RemoveEntryClicked);
            View.Search += new EventHandler<GenericEventArgs<string>>(View_Search);

            //Monitor Entry Provider Events
            Tracy.TracyFacade.Instance.EntryProvider.ItemsAdded += new EventHandler<GenericEventArgs<IList<Entry>>>(EntryProvider_ItemAdded);
            Tracy.TracyFacade.Instance.EntryProvider.ItemsChanged += new EventHandler<GenericEventArgs<IList<DataChangeSet<Entry>>>>(EntryProvider_ItemsChanged);
            Tracy.TracyFacade.Instance.EntryProvider.ItemsRemoved += new EventHandler<GenericEventArgs<IList<Entry>>>(EntryProvider_ItemRemoved);

            //Monitor MediaFile Provider Events
            Tracy.TracyFacade.Instance.MediaFileProvider.ItemsChanged += new EventHandler<GenericEventArgs<IList<DataChangeSet<MediaFile>>>>(MediaFileProvider_ItemsChanged);
            Tracy.TracyFacade.Instance.MediaFileProvider.ItemsAdded += new EventHandler<GenericEventArgs<IList<MediaFile>>>(MediaFileProvider_ItemsAdded);
            Tracy.TracyFacade.Instance.MediaFileProvider.ItemsRemoved += new EventHandler<GenericEventArgs<IList<MediaFile>>>(MediaFileProvider_ItemsRemoved);

            _ueViewController.EntriesFilteredOut += new EventHandler<SharedLib.GenericEventArgs<ICollection<Tracy.DataModel.Entry>>>(_ueViewController_EntriesFilteredOut);
            _ueViewController.Init();
        }



        #region View Events
        void View_CreateEntryClicked(object sender, EventArgs e)
        {
            Tracy.TracyFacade.Instance.ExceptionManager.Process(() =>
            {
                 EntryViewController entryVC = new EntryViewController(null);
                 entryVC.View.ShowModal();
            }, "UI Policy");
        }
        
        void View_EditEntryClicked(object sender, GenericEventArgs<Entry> e)
        {
            if (_selectedEntry != null)
            {
                Tracy.TracyFacade.Instance.ExceptionManager.Process(() =>
                {
                    EntryViewController entryVC = new EntryViewController(_selectedEntry);
                    entryVC.View.ShowModal();
                }, "UI Policy");
            }
        }
        
        void View_RemoveEntryClicked(object sender, GenericEventArgs<Entry> e)
        {
            if (_selectedEntry != null)
            {
                Tracy.TracyFacade.Instance.ExceptionManager.Process(() =>
                {
                    Tracy.TracyFacade.Instance.EntryProvider.RemoveItem(_selectedEntry);
                }, "UI Policy");
            }
        }

        void View_AllEntriesClicked(object sender, EventArgs e)
        {
            Tracy.TracyFacade.Instance.ExceptionManager.Process(() =>
            {
                _entryTabsViewController.SwitchToAllEntriesTab();
            }, "UI Policy");
        }

        void View_EntrySelected(object sender, GenericEventArgs<Entry> e)
        {
            Tracy.TracyFacade.Instance.ExceptionManager.Process(() =>
            {
                _selectedEntry = e.Data;
                _entryTabsViewController.SwitchToEntryTab(e.Data);
            }, "UI Policy");
        }

        void View_OpenEntryInNewTab(object sender, GenericEventArgs<Entry> e)
        {
            Tracy.TracyFacade.Instance.ExceptionManager.Process(() =>
            {
                _entryTabsViewController.SwitchToEntryTab(e.Data, true);
            }, "UI Policy");
        }

        void View_Search(object sender, GenericEventArgs<string> e)
        {
            Tracy.TracyFacade.Instance.ExceptionManager.Process(() =>
            {
                _entryTabsViewController.SwitchToSearchTab(e.Data);
                View.FocusOnSearchTextBox();
            }, "UI Policy");
        }
        #endregion

        #region Model Events
        void EntryProvider_ItemAdded(object sender, GenericEventArgs<IList<Entry>> e)
        {
            if (e.Data != null && e.Data.Count > 0)
            {
                LoadEntriesToView(e.Data, false);
                
                //Perform Scan on new entry
                List<Entry> entriesToScan = new List<Entry>();
                foreach (Entry entry in e.Data)
                {
                    if (!entry.TracingDisabled) entriesToScan.Add(entry);
                }
                if(entriesToScan.Count > 0)
                    Tracy.TracyFacade.Instance.MessageDispatcher.EnqueueMessage(new TaskMessage(this, typeof(FeedScanHandler), entriesToScan, null));
                
                //Select current entry
                View.SelectEntry(e.Data[0]);
            }
        }

        void EntryProvider_ItemsChanged(object sender, GenericEventArgs<IList<DataChangeSet<Entry>>> e)
        {
            List<Entry> entriesToScan = new List<Entry>();
            foreach (DataChangeSet<Entry> change in e.Data)
            {
                View.RefreshEntry(change.Data);
                if (!change.Data.TracingDisabled) entriesToScan.Add(change.Data);
                
            }
            if (entriesToScan.Count > 0)
                Tracy.TracyFacade.Instance.MessageDispatcher.EnqueueMessage(new TaskMessage(this, typeof(FeedScanHandler), entriesToScan, null));

        }
        

        void EntryProvider_ItemRemoved(object sender, GenericEventArgs<IList<Entry>> e)
        {
            foreach (Entry entry in e.Data)
            {
                if (entry == _selectedEntry) _selectedEntry = null;
                View.UnloadEntry(entry);
            }
        }

        private void RefreshRelatedEntries<T>(IList<T> itemList, Func<T, Entry> funcGetRelatedEntry, Func<T, bool> condition)
        {
            List<string> entriesToRefresh = new List<string>();
            foreach (T item in itemList)
            {

                if (condition(item))
                {
                    Entry entry = funcGetRelatedEntry(item);
                    if (entry != null && !string.IsNullOrEmpty(entry.ID))
                    {
                        string entry_id = entry.ID;
                        if (!String.IsNullOrEmpty(entry_id) && !entriesToRefresh.Contains(entry_id))
                        {
                            entriesToRefresh.Add(entry_id);
                        }
                    }
                }

            }
            foreach (string id in entriesToRefresh)
            {
                Entry entry = Tracy.TracyFacade.Instance.EntryProvider.GetItemByID(id);
                if(entry != null) View.RefreshEntry(entry);
            }

            if (_selectedEntry != null)
            {
                if (entriesToRefresh.Contains(_selectedEntry.ID))//If selected item got updated
                {
                    View.SelectEntry(_selectedEntry);//select again
                }
            }
        }

        void MediaFileProvider_ItemsChanged(object sender, GenericEventArgs<IList<DataChangeSet<MediaFile>>> e)
        {
            RefreshRelatedEntries(e.Data, change => change.Data.Resource.Entry, 
                change => change.OriginalData.Visible != change.Data.Visible ||
                    CommonHelper.CheckCriticalValueChange<MediaFile>(file => file.Status, "Ready", change.OriginalData, change.Data));
        }
        void MediaFileProvider_ItemsRemoved(object sender, GenericEventArgs<IList<MediaFile>> e)
        {
            RefreshRelatedEntries(e.Data, file => file.Resource.Entry, file => file.Visible == "true" && file.Status == "Ready");
        }

        void MediaFileProvider_ItemsAdded(object sender, GenericEventArgs<IList<MediaFile>> e)
        {
            RefreshRelatedEntries(e.Data, file => file.Resource.Entry, file => file.Visible == "true" && file.Status == "Ready");
        }
        
        #endregion

        #region UltraExplorer
        void _ueViewController_EntriesFilteredOut(object sender, SharedLib.GenericEventArgs<ICollection<Tracy.DataModel.Entry>> e)
        {
            LoadEntriesToView(e.Data);
        }
        #endregion

        #region Public Functions
        public void LoadEntriesToView(ICollection<Entry> entries, bool clearList = true)
        {
            if (clearList)
            {
                _selectedEntry = null;
                View.ClearEntries();
            }
            foreach (Entry entry in entries)
            {
                View.LoadEntry(entry);
            }
        }

        
        #endregion



        #region IHasViewState Members

        public void LoadViewState(ViewStateManager manager, System.Xml.XmlElement viewStateNode)
        {
            manager.LoadViewState(_entryTabsViewController, viewStateNode);
            manager.LoadViewState(_ueViewController, viewStateNode);
        }

        public void SaveViewState(ViewStateManager manager, System.Xml.XmlElement viewStateNode, System.Xml.XmlDocument doc)
        {
            manager.SaveViewState(_ueViewController, viewStateNode);
            manager.SaveViewState(_entryTabsViewController, viewStateNode);
        }

        #endregion
    }
}
